package com.yeziji.security;

import com.yeziji.security.component.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsConfigurationSource;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

/**
 * spring security 配置
 *
 * @author hwy
 * @since 2023/11/09 21:44
 **/
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity.csrf().disable()
                .formLogin().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling().accessDeniedHandler(this.requestAccessDeniedHandler()).authenticationEntryPoint(this.requestAuthenticationEntryPoint())
                .and()
                .addFilterBefore(this.jwtFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(this.dynamicSecurityFilter(), FilterSecurityInterceptor.class)
                .addFilterBefore(this.loggerFilter(), FilterSecurityInterceptor.class)
                .build();
    }

    /**
     * 配置跨源访问(CORS)
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }

    /**
     * 配置 jwt 拦截器
     */
    @Bean
    public JwtFilter jwtFilter() {
        return new JwtFilter();
    }

    /**
     * 日志拦截器
     */
    @Bean
    public LoggerFilter loggerFilter() {
        return new LoggerFilter();
    }

    /**
     * 认证异常：定义无权限访问时的操作
     */
    @Bean
    public RequestAccessDeniedHandler requestAccessDeniedHandler() {
        return new RequestAccessDeniedHandler();
    }

    /**
     * 认证异常：定义未登录或登录过期时的操作
     */
    @Bean
    public RequestAuthenticationEntryPoint requestAuthenticationEntryPoint() {
        return new RequestAuthenticationEntryPoint();
    }

    /**
     * 动态权限元数据获取器
     */
    @Bean
    public DynamicSecurityMetadataSource dynamicSecurityMetadataSource() {
        return new DynamicSecurityMetadataSource();
    }

    /**
     * 动态权限判断执行器
     */
    @Bean
    public DynamicAccessDecisionManager dynamicAccessDecisionManager() {
        return new DynamicAccessDecisionManager();
    }

    /**
     * 动态安全拦截器
     */
    @Bean
    public DynamicSecurityFilter dynamicSecurityFilter() {
        return new DynamicSecurityFilter();
    }
}
